package category

import (
	"fmt"
	"time"
	"yunj/app/data"
	"yunj/app/dto"
	"yunj/app/model"
	"yunj/app/service"
	"yunj/app/service/admin/categoryservice"
	"yunj/pkg/global"
	"yunj/pkg/yunj/app/controller/admin"
	"yunj/pkg/yunj/app/enum/stateenum"
	"yunj/pkg/yunj/app/service/admin/adminservice"
	"yunj/pkg/yunj/core/response"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type Category struct {
	admin.Controller
}

func (ctrl *Category) Index(ctx *gin.Context) {
	data := map[string]interface{}{}
	normalData := &dto.AdminCategoryPageIndexNormalData{
		DefaultAlias:          global.Config.Default.Category.Alias,
		LevelLimit:            global.Config.Default.Category.LevelLimit,
		EditUrl:               util.BuildAdminUrl("/category/edit"),
		TreeNodesUrl:          util.BuildAdminUrl("/category/tree-nodes"),
		HandleUrl:             util.BuildAdminUrl("/category/index-handle"),
		HasAddAuth:            adminservice.CheckAuth(ctx, "yunj_category_add"),
		HasEditAuth:           adminservice.CheckAuth(ctx, "yunj_category_edit"),
		HasRecycleBinAuth:     adminservice.CheckAuth(ctx, "yunj_category_recyle_bin"),
		HasRecycleBinListAuth: adminservice.CheckAuth(ctx, "yunj_category_recyle_bin_list"),
		HasSortAuth:           adminservice.CheckAuth(ctx, "yunj_category_sort"),
	}
	data["normal"] = normalData
	if normalData.HasRecycleBinListAuth {
		recycleBinListBuilder := categoryservice.CategoryPage.RecyleBinBuilder(ctx)
		recycleBinListBuilder.Assign()
		if ctx.IsAborted() {
			return
		}
		data["builderId"], _ = recycleBinListBuilder.GetId()
	}
	ctrl.Render(ctx, "category/index", data)
}

func (ctrl *Category) IndexHandle(ctx *gin.Context) {
	if !util.IsAsync(ctx) {
		response.Fail(ctx, "请使用异步请求")
		return
	}
	// 获取数据
	var param dto.AdminCategoryPageHandleParam
	ctx.ShouldBindJSON(&param)
	// 验证数据
	param.InitValidator(&param)
	if err := param.CheckScene(param.Event); err != nil {
		response.Fail(ctx, err.Error())
		return
	}
	// 数据处理
	if param.Event == "Add" {
		dbErr := global.MySQL.Create(param.InsertCategory).Error
		if dbErr != nil {
			response.Fail(ctx, fmt.Sprintf("添加分类异常！%v", dbErr))
			return
		}
		// 处理所有分类数据的完整属性值，并清理缓存
		err := data.HandleAllCategoryFullAttr()
		if err != nil {
			response.Fail(ctx, fmt.Sprintf("添加分类异常！%v", err))
			return
		}
		response.Success(ctx, dto.AdminCategoryAddResponse{Id: param.InsertCategory.Id, Name: param.InsertCategory.Name})
		return
	}
	if param.Event == "RecycleBin" {
		dbErr := global.MySQL.Model(&model.Category{}).Where("id = ? and state = ? and alias <> ?", param.Category.Id, stateenum.NORMAL, global.Config.Default.Category.Alias).Updates(map[string]any{
			"state":            stateenum.RECYLE_BIN,
			"last_update_time": time.Now().In(time.Local).Unix(),
		}).Error
		if dbErr != nil {
			response.Fail(ctx, fmt.Sprintf("分类移入回收站异常！%v", dbErr))
			return
		}
		// 处理所有分类数据的完整属性值，并清理缓存
		err := data.HandleAllCategoryFullAttr()
		if err != nil {
			response.Fail(ctx, fmt.Sprintf("分类移入回收站异常！%v", err))
			return
		}
		response.Success(ctx, nil)
		return
	}
	if param.Event == "Drag" {
		var dbErr error
		if param.Mode == "inner" {
			dbErr = global.MySQL.Save(param.Category).Error
			if dbErr != nil {
				dbErr = fmt.Errorf("移动到目标分类内部异常！%v", dbErr)
			}
		} else {
			dbErr = global.MySQL.Transaction(func(tx *gorm.DB) (err error) {
				err = tx.Save(param.Category).Error
				if err != nil {
					err = fmt.Errorf("移动到目标分类外部修改异常！%v", err)
					return
				}
				err = tx.Exec(param.DragSortSql).Error
				if err != nil {
					err = fmt.Errorf("移动到目标分类外部修改同级分类异常！%v", err)
				}
				return
			})
		}
		if dbErr != nil {
			response.Fail(ctx, fmt.Sprintf("分类排序异常！%v", dbErr))
			return
		}
		// 处理所有分类数据的完整属性值，并清理缓存
		err := data.HandleAllCategoryFullAttr()
		if err != nil {
			response.Fail(ctx, fmt.Sprintf("分类排序异常！%v", err))
			return
		}
		response.Success(ctx, nil)
		return
	}
	response.Fail(ctx, "未知处理事件")
}

func (ctrl *Category) TreeNodes(ctx *gin.Context) {
	if !util.IsAsync(ctx) {
		response.Fail(ctx, "请使用异步请求")
		return
	}
	nodes, err := service.Category.TreeNodes(0, nil)
	if err != nil {
		response.Fail(ctx, err.Error())
		return
	}
	response.Success(ctx, map[string]any{"nodes": nodes})
}

func (ctrl *Category) Edit(ctx *gin.Context) {
	ctrl.RenderForm(ctx, categoryservice.CategoryPage.EditBuilder(ctx))
}
